package cn.com.chengmandian.core.common.utils;

import cn.hutool.core.util.NumberUtil;

import java.awt.*;
import java.awt.geom.Point2D;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

public class LnglatUtil {
    public static void main(String[] args) {
        radii("102.86139138403291,102.86499011795888,102.86606560151938,102.86908522926865,102.86900249987752,102.86759609774572,102.8714430205805,102.87156711483749,102.87107073694028,102.86772019231819,102.86288051546705,102.8584131213081,102.85113292363553,102.84665238405307,102.83643577245937,102.8174079822835,102.80934185463252,102.80251667018342,102.79722198006925,102.77245074933103,102.77050523036019,102.76972701712464,102.77507720321125,102.78159470543574,102.78879313513914,102.79171141953998,102.78597212460659,102.78568029854432,102.77750910489749,102.77031068113865,102.79336511690724,102.82293705378652,102.8355564953024,102.83829446473362,102.84295672910912,102.85026901859771,102.85358491899069,102.85555642787153,102.85799292374543,102.86145839855783,102.86145839855783".split(","),
                "24.870836583070712,24.859840240319997,24.856762590403264,24.846065284406492,24.84180199321563,24.838798970994173,24.834219221637127,24.83324318763169,24.828250278667436,24.824984131233293,24.823557510438214,24.823557510868504,24.8187519328241,24.81732698448566,24.812556966949654,24.80579846957611,24.801217500948137,24.807788510064526,24.814997445404035,24.804998755725823,24.817448639863017,24.822746085166095,24.835547306050206,24.847817577944088,24.8512600971575,24.853908124803123,24.865853035385598,24.87573754749986,24.88924161484649,24.89577130497069,24.912094020812518,24.924974205973992,24.923702664303406,24.9208084546012,24.92132772864071,24.921493555633514,24.912314411395123,24.90313558751746,24.88293093340869,24.870974297742706,24.8706212794835".split(","));
    }

    private static double EARTH_RADIUS = 6378.137;

    private static double rad(double d) {
        return d * Math.PI / 180.0;
    }

    private final static double pi = 3.14159265358979324;
    /**
     * 获取多边形中心点
     */
    public static BigDecimal[] getCenterOfPolygon(String[] lngs, String[] lats) {
        double x = 0;
        double y = 0;
        double z = 0;
        for (int i = 0; i < lngs.length; i++) {
            double lng = (Double.parseDouble(lngs[i]) * Math.PI) / 180;
            double lat = (Double.parseDouble(lats[i]) * Math.PI) / 180;
            x = x + Math.cos(lat) * Math.cos(lng);
            y = y + Math.cos(lat) * Math.sin(lng);
            z = z + Math.sin(lat);
        }
        x = x / lngs.length;
        y = y / lngs.length;
        z = z / lngs.length;
        double Lng = Math.atan2(y, x);
        double Hyp = Math.sqrt(x * x + y * y);
        double Lat = Math.atan2(z, Hyp);
        return new BigDecimal[] {NumberUtil.round((Lng * 180) / Math.PI, 6, RoundingMode.HALF_UP), NumberUtil.round((Lat * 180) / Math.PI, 6, RoundingMode.HALF_UP)};
    }

    /**
     *  计算两点经纬度之间距离
     */
    public static double getDistance(Double originLon, Double originLat, Double destinationLon, Double destinationLat) {
        double radLat1 = rad(originLat);
        double radLat2 = rad(destinationLat);
        double a = radLat1 - radLat2;
        double b = rad(originLon) - rad(destinationLon);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
                + Math.cos(radLat1) * Math.cos(radLat2)
                * Math.pow(Math.sin(b / 2), 2)));
        s = s * EARTH_RADIUS;
        // 保留三位小数
        s = Math.round(s * 1000d) / 1000d;
        s = s * 1000;
        return s;
    }

    /**
     * 点，是否在多边形内
     */
    public static boolean isInPolygon(Double lng, Double lat, String[] lngs, String[] lats) {
        Point2D.Double point = new Point2D.Double(lng, lat);
        List<Point2D.Double> pts = new ArrayList<>();
        for(int i = 0; i < lngs.length; i ++) {
            pts.add(new Point2D.Double(Double.parseDouble(lngs[i]), Double.parseDouble(lats[i])));
        }
        return isInPolygon(point, pts);
    }

    /**
     * 点，是否在多边形内
     */
    public static boolean isInPolygon(Point2D.Double point, List<Point2D.Double> pts){
        int N = pts.size();
        boolean boundOrVertex = true;
        int intersectCount = 0;//交叉点数量
        double precision = 2e-10; //浮点类型计算时候与0比较时候的容差
        Point2D.Double p1, p2;//临近顶点
        Point2D.Double p = point; //当前点
        p1 = pts.get(0);
        for(int i = 1; i <= N; ++i){
            if(p.equals(p1)){
               return boundOrVertex;
            }

            p2 = pts.get(i % N);
            if(p.x < Math.min(p1.x, p2.x) || p.x > Math.max(p1.x, p2.x)){
                p1 = p2;
                continue;
            }

            //射线穿过算法
            if(p.x > Math.min(p1.x, p2.x) && p.x < Math.max(p1.x, p2.x)){
                if(p.y <= Math.max(p1.y, p2.y)){
                    if(p1.x == p2.x && p.y >= Math.min(p1.y, p2.y)){
                        return boundOrVertex;
                    }

                    if(p1.y == p2.y){
                        if(p1.y == p.y){
                            return boundOrVertex;
                        }else{
                            ++intersectCount;
                        }
                    }else{
                        double xinters = (p.x - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y;
                        if(Math.abs(p.y - xinters) < precision){
                            return boundOrVertex;
                        }

                        if(p.y < xinters){
                            ++intersectCount;
                        }
                    }
                }
            }else{
                if(p.x == p2.x && p.y <= p2.y){
                    Point2D.Double p3 = pts.get((i+1) % N);
                    if(p.x >= Math.min(p1.x, p3.x) && p.x <= Math.max(p1.x, p3.x)){
                        ++intersectCount;
                    }else{
                        intersectCount += 2;
                    }
                }
            }
            p1 = p2;
        }
        if(intersectCount % 2 == 0){//偶数在多边形外
            return false;
        } else { //奇数在多边形内
            return true;
        }
     }

    /**
     * 点到线段间距离
     */
    public static double pointToLineDistance(Double x, Double y, Double point1x, Double point1y, Double point2x, Double point2y) {
        double dis = 0;
        double a, b, c;
        a = getDistance(point1x, point1y, point2x, point2y);// 线段的长度
        b = getDistance(point1x, point1y, x, y); // point1到点的距离
        c = getDistance(point2x, point2y, x, y);//point2到点的距离
        if(c + b == a) { // 点在线段上
            dis = 0;
            return dis;
        }
        if(c * c >= a * a + b * b) {// 组成直角三角形或钝角三角形，投影在point1延长线上，
            dis = b;
            return dis;
        }
        if(b * b >= a * a + c * c) {// 组成直角三角形或钝角三角形，投影在point2延长线上，
            dis = c;
            return dis;
        }
        // 组成锐角三角形，则求三角形的高
        double p = (a + b + c) /2; // 半周长
        double s = Math.sqrt(p * (p - a) * (p - b) * (p - c));// 海伦公式求面积
        dis = 2* s / a;// 返回点到线的距离(利用三角形面积公式求高)
        return Math.round(dis);
    }

    /**
     * a
     */
    private final static double a = 6378245.0;
    /**
     * ee
     */
    private final static double ee = 0.00669342162296594323;

    /**
     * @Description WGS84 to 火星坐标系 (GCJ-02)
     * @param lon  经度
     * @param lat  纬度
     * @return
     */
    public static double[] wgs84ToGcj02(double lon, double lat) {
//        if (outOfChina(lat, lon)) {
//            return null;
//        }
        double dLat = transformLat(lon - 105.0, lat - 35.0);
        double dLon = transformLon(lon - 105.0, lat - 35.0);
        double radLat = lat / 180.0 * pi;
        double magic = Math.sin(radLat);
        magic = 1 - ee * magic * magic;
        double sqrtMagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
        dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
        double mgLat = lat + dLat;
        double mgLon = lon + dLon;
        return new double[]{mgLon, mgLat};
    }

    /**
     * @Description 判断是否在中国范围内
     * @param lat
     * @param lon
     * @return
     */
    public static boolean outOfChina(double lat, double lon) {
        if (lon < 72.004 || lon > 137.8347)
            return true;
        if (lat < 0.8293 || lat > 55.8271)
            return true;
        return false;
    }


    /**
     * @Description transformLat
     * @param x
     * @param y
     * @return
     */
    private static double transformLat(double x, double y) {
        double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y
                + 0.2 * Math.sqrt(Math.abs(x));
        ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
        ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
        return ret;
    }

    /**
     * @Description transformLon
     * @param x
     * @param y
     * @return
     */
    public static double transformLon(double x, double y) {
        double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1
                * Math.sqrt(Math.abs(x));
        ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
        ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0
                * pi)) * 2.0 / 3.0;
        return ret;
    }

    /**
     * 区域最大半径
     */
    public static int radii(String[] lngs, String[] lats){
        // 区域中心点
        BigDecimal[] lngLats = LnglatUtil.getCenterOfPolygon(lngs,lats);
        BigDecimal centerLat = lngLats[1];
        BigDecimal centerLng = lngLats[0];

        List<Double>  distances = new ArrayList<>();
        for(int i = 0; i< lngs.length; i++){
            Double lng = Double.valueOf(lngs[i]);
            Double lat = Double.valueOf(lats[i]);

            Double distance = getDistance(centerLng.doubleValue(),centerLat.doubleValue(),lng,lat);
            distances.add(distance);
        }

        int Size = distances.size();
        for (int i = 0; i < Size; i++) {
            for(int j=0;j<Size-1-i;j++){
                Double book1 =  distances.get(j);
                Double book2 =  distances.get(j+1);
                if (book1 < book2){
                    distances.set(j,book2);
                    distances.set(j+1,book1);

                }
            }

        }
        return distances.get(0).intValue();
    }
}
